<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-type" content="text/html;charset=utf-8">
        <title> Avoiding Memory Leakss </title>
        <link rel="stylesheet" type="text/css" href="print.css" />
    </head>
    
    <body>
    <h1>Avoiding Memory Leaks</h1>
      <div> 
        <p>
            Android程序，至少对于T-Mobile G1来说，堆区限制在16M。这对于电话来说可是说是很多的内存，
            但是对于某些开发者来说又算是很少。虽然你并没有打算使用所有的内存，你应该让你的程序使用尽可能少的内存，以避免你的应用被杀死。Android能够在内存中保留的程序越多，对于用户来说在任意两个程序之间切换的速度就越快！在我的工作中，在Android中我所遇到的关于内存泄漏的问题，大多数都是因为同样的错误：保存一个对于<code>Context</code> 的长期引用。   
        </p>
        
      <div>
        在android中，一个<code>Context</code>可用于很多操作，但是最多的是加载资源和访问资源。
        这就是为什么所以的小部件都在他们的构造函数中接收一个Context参数。在一个普通的android应用中，
        你通常有两种类型的<code>Context<code>,Activity和Application.通常开发者传递到需要一个<code>Context</code>的类中和方法中去的是第一个：
        <pre>
            @Override
            protected void onCreate(Bundle state){
                super.onCreate(state);
                TextView label = new TextView(this);
                label.setText("Leaks are bad");
                
                setContentView(label);
            }
        </pre>
        <p>
            这意味着那个view有一个对于整个activity的引用即对于你的activty中的任何东西;
            通常整个view层级和所有的资源。因此，如果你漏泄了<code>Context</code>
            ("泄漏”是指你保存了一个指向它的引用，从而阻止了GC回收它。），你就泄漏了很多的内存。
            如果你不小心的话，泄漏一整个activity是很容易的。
        </p>
      </div>
      
      <div>
        <p>
            当屏幕方向改变的时候，默认情况下系统将销毁当前的activity同时创建一个新的并保存它的状态。
            执行这些操作的时候，Android将从资源中重新加载应用的UI。现在想像一下应用中有很大的图片，你不想在每次屏幕旋转的时候重新加载它，最简单的保存它并不在每次旋转的时候重新加载的方式就是将其保存为一个静态字段:
            <pre>
private static Drawable sBackground;

@Override
protected void onCreate(Bundle state){
    super.onCreate(state);
    
    TextView label = new TextView(this);
    label.setText("Leaks are bad");
    if(sBackground == null){
        sBackground = getDrawable(R.drawable.large_bitmap);
    }
    label.setBackgroundDrawable(sBackground);
    setContentView(label);
}
            </pre>
            这个代码很快，同时也错得可以;它在第一次屏幕方向改变的时候泄漏了第一次创建的activity。当一个<code>Drawable</code>依附于一个view的时候这个view被设置为这个drawable的<code>callback</code>.如上面的代码片段所示，那意味着,这个drawable有一个指向TextView的引用，而同时TextView有一个指向activity(即<code>Context</code>)，而这个<code>Context</code>又引用了很多东西（取决于你的代码）。
        </p>
        <p>
        这是一个很简单的关于泄漏<code>Context</code>的类，你可以在<quote>Home screen's source code</quote>(查找<code>unbindDrawables()</code>方法）中看到如何处理这种问题的，当这个activity要被销毁的时候设置一个保存drawable的回调函数为null。更有意思的是，当你创建了一个泄漏链的时候，这个链会让你的应用内存溢出更快。
        </p>
        <p>
            这是有两个避免Context相关的内存泄漏的简单的方法。最明显的一个就是，避免让context离开在它的自己的范围。上面的例子中，展示了一个静态引用，但是它的内部类及对于外部类的隐式引用同样危险。第二个解决方案就是
            使用<code>Application</code> context.这个context将会一直存活直到你的应用退出。它并不依赖activity的生命同期。如果打算保存一个需要长期引用的对象并且需要一个context，请记得使用application context.
            你可以通过调用<code>Context.getApplicationContext()</code>或者<code>Activity.getApplication()</code>
        </p>
      
      </div>
      
      </div>
      
      <div>
        总结，为了避免context相关的内在泄漏，请记住以下几点：
        <ul>
            <li>不要保存对context-activity的长期引用(一个对一个activity的引用应该与activity本身具有相同的生存周期)</li>
             <li>尽量使用context-application而不是一个context-activity</li>
              <li>避免在一个activity中的非静态内部类，如果你没有控制他们的生存周期的话，使用一个静态内部类并将其保存一个到activity的弱引用。这个解决方法是保存一个对于外部类的弱引用，正如在<code>ViewRoot</code>中所做的一样，它的W内部类.</li>
               <li>垃圾收集器并不是内在泄漏的保险</li>
        </ul>
      </div>
    </body>
</html>


































